package com.zs.oauth2.oauth2authorizationserver.config;

import com.zs.oauth2.common.service.handler.FormAuthenticationFailureHandler;
import com.zs.oauth2.common.service.handler.SsoLogoutSuccessHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * @author madison
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

//    @Autowired
//    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //取得RequestMatcherConfigurer对象并配置允许过滤的路由
                //如requestMatchers().anyRequest()等同于http.authorizeRequests().anyRequest().access("permitAll") {同authorizeRequests().anyRequest().permitAll()}
//                .requestMatchers().anyRequest()
//                .and()

                // 加上不然oauth/authorize 无权访问

                //        form-login是spring security命名空间配置登录相关信息的标签,它包含如下属性：
                //        1. login-page 自定义登录页url,默认为/login
                //        2. login-processing-url 登录请求拦截的url,也就是form表单提交时指定的action
                //        3. default-target-url 默认登录成功后跳转的url
                //        4. always-use-default-target 是否总是使用默认的登录成功后跳转url
                //        5. authentication-failure-url 登录失败后跳转的url
                //        6. username-parameter 用户名的请求字段 默认为userName
                //        7. password-parameter 密码的请求字段 默认为password
                //        8. authentication-success-handler-ref 指向一个AuthenticationSuccessHandler用于处理认证成功的请求
                //              不能和default-target-url还有always-use-default-target同时使用
                //        9. authentication-success-forward-url 用于authentication-failure-handler-ref
                //        10. authentication-failure-handler-ref 指向一个AuthenticationFailureHandler用于处理失败的认证请求
                //        11. authentication-failure-forward-url 用于authentication-failure-handler-ref
                //        12. authentication-details-source-ref 指向一个AuthenticationDetailsSource,在认证过滤器中使用
                .formLogin()
//                .permitAll()
                .loginPage("/token/login")//用户未登录时，访问任何资源都转跳到该路径，即登录页面
                .loginProcessingUrl("/token/form")//登录表单form中action的地址，也就是处理认证请求的路径
//                .usernameParameter("uname")///登录表单form中用户名输入框input的name名，不修改的话默认是username
//                .passwordParameter("pword")//form中密码输入框input的name名，不修改的话默认是password
//                .defaultSuccessUrl("/index")//登录认证成功后默认转跳的路径
                .failureHandler(authenticationFailureHandler()).and().logout()
                .logoutSuccessHandler(logoutSuccessHandler()).deleteCookies("JSESSIONID").invalidateHttpSession(true)
                .and()
                // 不然自定义的登录页面没法进去
                .authorizeRequests().antMatchers("/token/**", "/actuator/**", "/mobile/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/css/**");
    }

//    @Override
//    public UserDetailsService userDetailsService() {
//        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
//        manager.createUser(User.withUsername("admin").password(passwordEncoder().encode("admin")).roles("ADMIN").build());
//        manager.createUser(User.withUsername("user").password(passwordEncoder().encode("123456")).roles("USER").build());
//        return manager;
//    }

//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth
////                .userDetailsService(userDetailsService())
//                .userDetailsService(userDetailsService)
//                .passwordEncoder(passwordEncoder());
//    }

    /**
     * 不加报错
     * Parameter 1 of constructor in com.zs.security.springsecurityoauth2resourceserver.config.OAuth2AuthorizationConfig
     * required a bean of type 'org.springframework.security.authentication.AuthenticationManager' that could not be found.
     * <p>
     * 和 OAuth2AuthorizationConfig 里面的 endpoints.authenticationManager(authenticationManager) 一起使用
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
//
//    @Bean
//    public PasswordEncoder passwordEncoder() {
//        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
//    }


    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new FormAuthenticationFailureHandler();
    }

    /**
     * 支持SSO 退出
     *
     * @return LogoutSuccessHandler
     */
    @Bean
    public LogoutSuccessHandler logoutSuccessHandler() {
        return new SsoLogoutSuccessHandler();
    }
}